/*
 * Filename : SOCInstallBaseController.java 
 * Package : com.spi.soconversion
 * Created by: Software Paradigms International Group, LLC. (SPI) 
 * Copyright (c) 2010 HBC
 */

package com.spi.soconversion;

import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.sql.Connection;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
import java.sql.Timestamp;
import java.util.Properties;

import com.spi.soconversion.base.SOCException;
import com.spi.soconversion.base.data.InstallBaseDataProcessor;
import com.spi.soconversion.jmsqueue.JMSInitializer;
import com.spi.soconversion.orders.SOCFetchInstallBase;
import com.spi.soconversion.util.BatchProcessor;
import com.spi.soconversion.util.ConversionType;
import com.spi.soconversion.util.DBConnection;
import com.spi.soconversion.util.ErrorConstants;
import com.spi.soconversion.util.ErrorMessageReader;
import com.spi.soconversion.util.QueryConstants;
import com.spi.soconversion.util.QueryReader;
import com.spi.soconversion.util.SOCConstants;
import com.spi.soconversion.util.SOCFileWriter;
import com.spi.soconversion.util.SOCUtility;
import com.spi.soconversion.util.XMLValidator;



/**
 * This class is the single entry point to the Sales Order Conversion Application.
 * It Controls the Data Loading from COFI components to MCF System 
 * by using XML files. 
 * <p>
 * Issues:
 * <p>
 * NONE
 * <p>
 * History:
 * <p>
 * <ul>
 * <li>2010.04.17 pk: created
 * </ul>
 *
 * @author Priya Khanna, SPI (pk)
 */

public class InstallBaseController {

	private String d_xmlOutputDirectory;
	private String d_host;
	private String d_service;
	private String d_user;
	private String d_password;
	private String d_conversionType ;
	private Connection d_connection;
	private int d_batchNum=0;
	private int d_lastBatch=0;
	private int d_batchSize;
	private int d_totalRecordsProcessed;
	private long d_totalGoodRecords;
	private String d_logFileDirectory;
	private String d_xsdDirectory;
	private String d_fetchInstallBaseData;
	private SOCFileWriter d_FileWriter;
	private String d_logFileName;
	private String 	d_statisticsFile;
	private Timestamp startTime;
	private Timestamp endTime;
	private JMSInitializer jmsInitializer;
	
		
	/**
     * This method initializes the controller and processes the passed inputs.
     * @param args - string array of the command line arguments passed to the application
     * @throws SOCException - wraps all the exceptions that occur while processing
     */
    public void init(String propertyFilePath) throws SOCException
    {
    	Properties props = new Properties();
        
        try {
        	props.load(new FileInputStream(propertyFilePath));
		} catch (IOException e) {
			throw new SOCException("I/O Exception occurred while reading file - "+propertyFilePath);
		}	
        d_logFileDirectory = props.getProperty("logdirectoryPath");
        if(d_logFileDirectory==null)
        {
        	throw new SOCException(
            		ErrorMessageReader.getError(
            				ErrorConstants.MISSING_LOG_DIRECTORY));
        }
        if(!SOCUtility.checkDirectory(d_logFileDirectory))
		{
			throw new SOCException(
            		ErrorMessageReader.getError(
            				ErrorConstants.INVALID_OUTPUT_DIRECTORY)+d_logFileDirectory);
		}
        
        d_FileWriter = new SOCFileWriter();
    	String timeStamp =  SOCUtility.dateSuffix();
   		d_logFileName= d_logFileDirectory+SOCConstants.DELIMITER+SOCConstants.INSTALL_BASE_LOG_FILE+SOCConstants.UNDERSCORE+timeStamp+SOCConstants.LOG_FILE_EXTN;
    	        
        d_xmlOutputDirectory = props.getProperty("xmldirectoryPath");
        if(d_xmlOutputDirectory==null)
        {
        	d_FileWriter.write(d_logFileName, SOCUtility.writeLogMessage(ErrorMessageReader.getError(
    				ErrorConstants.MISSING_XML_DIRECTORY)));
        	throw new SOCException(
            		ErrorMessageReader.getError(
            				ErrorConstants.MISSING_XML_DIRECTORY));
        }
        if(!SOCUtility.checkDirectory(d_xmlOutputDirectory))
		{
        	d_FileWriter.write(d_logFileName, SOCUtility.writeLogMessage(ErrorMessageReader.getError(
    				ErrorConstants.INVALID_OUTPUT_DIRECTORY)+d_xmlOutputDirectory));
        	throw new SOCException(
            		ErrorMessageReader.getError(
            				ErrorConstants.INVALID_OUTPUT_DIRECTORY)+d_xmlOutputDirectory);
		}
        
        d_xsdDirectory = props.getProperty("xsddirectoryPath");
        if(d_xsdDirectory==null)
        {
        	d_FileWriter.write(d_logFileName, SOCUtility.writeLogMessage(ErrorMessageReader.getError(
    				ErrorConstants.MISSING_XSD_DIRECTORY)));
        	throw new SOCException(
            		ErrorMessageReader.getError(
            				ErrorConstants.MISSING_XSD_DIRECTORY));
        }
        if(!SOCUtility.checkDirectory(d_xsdDirectory))
		{
        	d_FileWriter.write(d_logFileName, SOCUtility.writeLogMessage(ErrorMessageReader.getError(
    				ErrorConstants.INVALID_OUTPUT_DIRECTORY)+d_xsdDirectory));
        	throw new SOCException(
            		ErrorMessageReader.getError(
            				ErrorConstants.INVALID_OUTPUT_DIRECTORY)+d_xsdDirectory);
		}
        
       
        
        d_user = props.getProperty("dbuser");
        if(d_user==null)
        {
        	d_FileWriter.write(d_logFileName, SOCUtility.writeLogMessage(ErrorMessageReader.getError(
    				ErrorConstants.MISSING_DATABASE_USER)));
        	throw new SOCException(
            		ErrorMessageReader.getError(
            				ErrorConstants.MISSING_DATABASE_USER));
        }

        d_password = props.getProperty("dbpassword");
        if(d_password==null)
        {
        	d_FileWriter.write(d_logFileName, SOCUtility.writeLogMessage(ErrorMessageReader.getError(
    				ErrorConstants.MISSING_DATABASE_PASSWORD)));
        	throw new SOCException(
            		ErrorMessageReader.getError(
            				ErrorConstants.MISSING_DATABASE_PASSWORD));
        }
        d_host = props.getProperty("dbhost");
        if(d_host==null)
        {
        	d_FileWriter.write(d_logFileName, SOCUtility.writeLogMessage(ErrorMessageReader.getError(
    				ErrorConstants.MISSING_DATABASE_HOST)));
        	throw new SOCException(
            		ErrorMessageReader.getError(
            				ErrorConstants.MISSING_DATABASE_HOST));
        }

        d_service = props.getProperty("dbservice");
        if(d_service==null)
        {
        	d_FileWriter.write(d_logFileName, SOCUtility.writeLogMessage(ErrorMessageReader.getError(
    				ErrorConstants.MISSING_DATABASE_SERVICE)));
        	throw new SOCException(
            		ErrorMessageReader.getError(
            				ErrorConstants.MISSING_DATABASE_SERVICE));
        }
        String batchSize = props.getProperty("batchSize");
        if(batchSize==null)
        {
        	d_FileWriter.write(d_logFileName, SOCUtility.writeLogMessage(ErrorMessageReader.getError(
    				ErrorConstants.MISSING_BATCH_SIZE)));
        	throw new SOCException(
            		ErrorMessageReader.getError(
            				ErrorConstants.MISSING_BATCH_SIZE));
        }
        try {

        	d_batchSize=Integer.parseInt(batchSize);
        
        } catch (NumberFormatException nfe) {
        	d_FileWriter.write(d_logFileName, SOCUtility.writeLogMessage(ErrorMessageReader.getError(
    				ErrorConstants.INVALID_BATCH_SIZE)+ batchSize));
        	throw new SOCException(
            		ErrorMessageReader.getError(
            				ErrorConstants.INVALID_BATCH_SIZE)+batchSize,nfe);
        }
        if(d_batchSize<0)
        {
        	d_FileWriter.write(d_logFileName, SOCUtility.writeLogMessage(ErrorMessageReader.getError(
    				ErrorConstants.INVALID_BATCH_SIZE_NOT_POSITIVE_NUMBER) + batchSize));
        	throw new SOCException(
            		ErrorMessageReader.getError(
            				ErrorConstants.INVALID_BATCH_SIZE_NOT_POSITIVE_NUMBER)+batchSize);
        }
      
        d_fetchInstallBaseData = props.getProperty("fetchInstallBaseData");
        if(d_fetchInstallBaseData==null)
        {
        	d_FileWriter.write(d_logFileName, SOCUtility.writeLogMessage(ErrorMessageReader.getError(
    				ErrorConstants.MISSING_FETCH_INSTALLBASE_DATA_FLAG)));
        	throw new SOCException(
            		ErrorMessageReader.getError(
            				ErrorConstants.MISSING_FETCH_INSTALLBASE_DATA_FLAG));
        }
        
        if(!"N".equals(d_fetchInstallBaseData) && !"Y".equals(d_fetchInstallBaseData) )
        {
        	d_FileWriter.write(d_logFileName, SOCUtility.writeLogMessage(ErrorMessageReader.getError(
    				ErrorConstants.INVALLID_VALUE_FOR_FETCHINSTALLBASEDATAONLY_FLAG)+ SOCConstants.BLANK_STRING+d_fetchInstallBaseData));
        	throw new SOCException(
            		ErrorMessageReader.getError(
            				ErrorConstants.INVALLID_VALUE_FOR_FETCHINSTALLBASEDATAONLY_FLAG));
        }
        
      	d_connection = DBConnection.getConnection(d_host,d_service,d_user,d_password); 	
    }
    
    /**
     * This is the entry point to the application.
     * @param args - arguments for the Sales Order Conversion Application
     */
    public static void main(String[] args)
    {
    	InstallBaseController controller = new InstallBaseController();
    	try
        {      	
           	if(args==null )
            {
              	throw new SOCException(
                  		ErrorMessageReader.getError(
                  				ErrorConstants.MISSING_INPUT_PARAMETERS));
            }
            if(args.length!=1)
            {
              	throw new SOCException(
                  		ErrorMessageReader.getError(
                  				ErrorConstants.MISSING_CONFIG_PROPERTY_FILE));
            }
            if(!args[0].endsWith(".properties"))
            {
              	throw new SOCException(
                  		ErrorMessageReader.getError(
                  				ErrorConstants.INVALID_CONFIG_PROPERTY_FILE));
            }
        	controller.init(args[0]);
            controller.fetch();
            controller.process();           
          
        }
        catch (SOCException soe)
        {
        	System.out.println(
        			SOCConstants.NEW_LINE
                    + SOCConstants.CONVERSION_NOT_PERFORM_INSTALL_BASE
                    + SOCConstants.NEW_LINE
                    + soe.getMessage());
            System.exit(1);
        }
        finally{
			try {
				controller.closeFiles();
				DBConnection.closeConnection();
			} catch (SOCException soe) {
				System.out.println(
						SOCConstants.NEW_LINE
						+ SOCConstants.CONVERSION_NOT_PERFORM_QUEUE
						+ SOCConstants.NEW_LINE
						+ soe.getMessage());
				soe.printStackTrace();
				System.exit(0);
			}
		}
    }
    
    /**
     * This Method processes the controls the conversion flow based on d_conversionType. 
     * @throws SOCException - wraps all the exceptions that occur while processing
     */
    public void process() throws SOCException
    {
    	BatchProcessor sbprocessor = null;
    	
    	if("N".equals(d_fetchInstallBaseData))
    	{
    		startTime = new Timestamp(System.currentTimeMillis());
    		sbprocessor =  new BatchProcessor(d_logFileName,d_FileWriter);
    	    	
	    	d_lastBatch = sbprocessor.getBatchNumber(ConversionType.INSTALLBASE.getDisplayText());
	    	int totalRecProcessed=0;
	    	if(d_lastBatch>0)
	      	{
	      		totalRecProcessed=sbprocessor.getTotalRecordsProcessed(d_lastBatch,ConversionType.INSTALLBASE.getDisplayText());
	      	}
	    	d_batchNum= d_lastBatch+1; 
	    	
	    	d_xmlOutputDirectory=d_xmlOutputDirectory+
	    						SOCConstants.DELIMITER+
	    						SOCConstants.BATCH+
	    						SOCConstants.UNDERSCORE+
								SOCConstants.INSTALL_BASE +
								SOCConstants.UNDERSCORE + 	    						
	    						d_batchNum;
	    	
	    	//renaming log file
	    	File logFile = new File(d_logFileName);
	    	String timeStamp = d_logFileName.substring(d_logFileName.indexOf(SOCConstants.UNDERSCORE), d_logFileName.length());
	    	String log= SOCConstants.INSTALL_BASE_LOG_FILE+SOCConstants.UNDERSCORE+SOCConstants.BATCH+d_batchNum+timeStamp;
	    	boolean renameLogFile = false;
	    	d_FileWriter.closeFile(d_logFileName);
	    	renameLogFile=logFile.renameTo(new File(d_logFileDirectory, log));
	    	d_statisticsFile = d_logFileDirectory+SOCConstants.DELIMITER+SOCConstants.EXECUTION_SUMMARY_FILE+SOCConstants.INSTALL_BASE_LOG_FILE+SOCConstants.UNDERSCORE+SOCConstants.BATCH+d_batchNum+timeStamp;
	    	if(renameLogFile) {
	    		d_logFileName=d_logFileDirectory+SOCConstants.DELIMITER+log;
	    	} else {
	    		d_FileWriter.write(d_logFileName, SOCUtility.writeLogMessage(ErrorMessageReader.getError(
	      				ErrorConstants.FAILED_RENAME_LOG_FILE)+log));
	    		throw new SOCException(
						ErrorMessageReader.getError(
	  				 ErrorConstants.FAILED_RENAME_LOG_FILE)+log);
	    	}
	    	File XMLDirRef= new File(d_xmlOutputDirectory);
	    	if (XMLDirRef.exists())
	        {
	    		d_FileWriter.write(d_logFileName, SOCUtility.writeLogMessage(ErrorMessageReader.getError(
	      				ErrorConstants.BATCH_ALREADY_RUN)+d_batchNum));
	    		throw new SOCException(
					ErrorMessageReader.getError(
					 ErrorConstants.BATCH_ALREADY_RUN)+d_batchNum);
	        }
	    	else
	    	{
	    		XMLDirRef.mkdir();
	    	}
	    	InstallBaseDataProcessor sbp = new InstallBaseDataProcessor(d_batchSize,totalRecProcessed,d_logFileName,d_FileWriter,d_xmlOutputDirectory,d_batchNum);
	    	
	    	d_totalRecordsProcessed= sbp.processRecords();
	    	int recordsFetched = sbp.getRecordsFetched();
	    
	    	validateXML();
	    	
	    	endTime = new Timestamp(System.currentTimeMillis());
	    	    	
	    	int recordsProcessed = 0;
			if(d_batchSize>0)
			{
				recordsProcessed=d_batchSize;
			}
			else
			{
				recordsProcessed=recordsFetched;
			}
			int recordsDataIssues= recordsProcessed-sbp.getCountXMLCreated();
			long recordsFailedValidation = sbp.getCountXMLCreated()- d_totalGoodRecords;
			
			sbprocessor.updateBatchInfo(d_batchNum,d_totalRecordsProcessed,recordsProcessed,recordsDataIssues,recordsFailedValidation,ConversionType.INSTALLBASE.getDisplayText(),startTime,endTime);		
			writeStatistics(recordsProcessed,sbp.getCountXMLCreated());
			d_conversionType = ConversionType.INSTALLBASE.getDisplayText();
			jmsInitializer = new JMSInitializer(d_xmlOutputDirectory,d_batchNum,d_logFileName, d_FileWriter,d_conversionType);
			jmsInitializer.getDirectoriesForJMSQueue();
			jmsInitializer.sendFileToJMSQueue();
    	}
	}
    
    public void fetch() throws SOCException
    {
    	if("Y".equals(d_fetchInstallBaseData))
    	{
    		SOCFetchInstallBase scf = new SOCFetchInstallBase(d_logFileName,d_FileWriter);
    		scf.fetchInstallBaseData();
    	}
    }
    
    /**
     * This Method gets the total records to be processed from FLATTABLE_INSTALLBASE. 
     * @throws SOCException - wraps all the exceptions that occur while processing
     */
    private int getTotalRecordsToBeProcessed() throws SOCException
    {
    	int result = 0;
    	String totalRecQuery = QueryReader.getQuery(QueryConstants.SELECT_TOTAL_RECORDS_TO_BE_PROCESSED_QUERY);
    	Statement stmt=null;
    	ResultSet rsInfo=null;
    	d_FileWriter.write(d_logFileName, SOCUtility.writeLogMessage(SOCConstants.MESSAGE_RETRIEVE_TOTAL_RECORDS_TO_BE_PROCESSED_STARTS));
    	try
		{
    		stmt=d_connection.createStatement();
    		rsInfo=stmt.executeQuery(totalRecQuery);
			if(rsInfo!=null)
			{
				rsInfo.next();
				result= rsInfo.getInt("TOTAL_COUNT");
				
			}			
		}
		catch(SQLException sqle)
		{
			d_FileWriter.write(d_logFileName, SOCUtility.writeLogMessage(ErrorMessageReader.getError(
    				ErrorConstants.FAILED_FETCH_TOTAL_RECORDS)+SOCConstants.NEW_LINE+sqle.getMessage()));
			throw new SOCException(
            		ErrorMessageReader.getError(
            				ErrorConstants.FAILED_FETCH_TOTAL_RECORDS) ,sqle);
    		
		}	
		d_FileWriter.write(d_logFileName, SOCUtility.writeLogMessage(SOCConstants.MESSAGE_RETRIEVE_TOTAL_RECORDS_TO_BE_PROCESSED_ENDS));
		return result;
    }
    
    
	
	private void writeStatistics(int recordsProcessed, int xmlCount) throws SOCException
	{
		d_FileWriter.write(d_statisticsFile,SOCConstants.MESSAGE_BATCH_NUMBER+d_batchNum+SOCConstants.NEW_LINE);    	
		d_FileWriter.write(d_statisticsFile,SOCConstants.MESSAGE_TOTAL_RECORDS_CONVERTED+getTotalRecordsToBeProcessed()+SOCConstants.NEW_LINE);
		// fix this
		d_FileWriter.write(d_statisticsFile,SOCConstants.MESSAGE_TOTAL_RECORDS_PROCESSED_TILL_BATCH+d_totalRecordsProcessed+SOCConstants.NEW_LINE);
		
		d_FileWriter.write(d_statisticsFile,SOCConstants.MESSAGE_TOTAL_RECORDS_PROCESSED_BATCH+recordsProcessed+SOCConstants.NEW_LINE);
		d_FileWriter.write(d_statisticsFile,SOCConstants.MESSAGE_TOTAL_RECORDS_DATA_ISSUES_BATCH+(recordsProcessed-xmlCount)+SOCConstants.NEW_LINE);		
		d_FileWriter.write(d_statisticsFile,SOCConstants.MESSAGE_TOTAL_RECORDS_CONVERTED_TO_XMLS_SUCCESSFULLY+xmlCount+SOCConstants.NEW_LINE);		
		d_FileWriter.write(d_statisticsFile,SOCConstants.MESSAGE_TOTAL_XMLS_PASSED_VALIDATION+d_totalGoodRecords+SOCConstants.NEW_LINE);
		
	}
	
	private void closeFiles() throws SOCException
	{
		if(d_FileWriter!=null)
		{
			d_FileWriter.closeFile(d_statisticsFile);			 

			d_FileWriter.closeFile(d_logFileName);   
		}
	}
	
	private void validateXML() throws SOCException
	{
		String xsdPath = d_xsdDirectory+SOCConstants.DELIMITER+SOCConstants.INSTALLBASE_XSD;
		XMLValidator validator= new XMLValidator(d_logFileName,d_FileWriter, xsdPath,SOCConstants.INSTALL_BASE_XML_FILE,d_batchNum);
		
		d_totalGoodRecords=validator.validateXML(d_xmlOutputDirectory );		
	}  
}
